﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using IndoorPositionFinder;
using System.Threading;
using Socket;
using System.Media;
using TextToSpeech;
using System.IO;

namespace RoomDisplay
{
    public partial class Form1 : Form
    {
        private XmlProcessor xmlStatus;
        private Room room;
        private WiimoteRecognizer recognizer;
        private Graphics graphics;
        private Thread t;
        private delegate void DrawPosition();
        private float ratio;
        private bool repaint;
        private String xmlPath, schemaPath; 

        public Form1()
        {
            this.repaint = false;
            this.xmlPath = "D:\\Proyectos\\IndoorPositionFinder\\IndoorPositionFinder\\IndoorMaps\\livingRoom.xml";
            this.schemaPath = "D:\\Proyectos\\IndoorPositionFinder\\IndoorPositionFinder\\IndoorMaps\\indoorMaps.xsd";
            InitializeComponent();
            this.SetStyle(ControlStyles.AllPaintingInWmPaint |
                          ControlStyles.UserPaint |
                          ControlStyles.DoubleBuffer, true);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            textBox1.ScrollBars = ScrollBars.Both;
            textBox1.ReadOnly = true;
            textBox2.ReadOnly = true;
            object[] comboData = new object[50];
            for (int i = 0; i < 50; i++)
                comboData[i] = (i + 1) * 2;
            this.comboBox1.Items.AddRange(comboData);
            this.comboBox1.SelectedItem = comboData[comboData.Length / 3];
        }
        private void drawUserPosition()
        {
            Point roomMax = new Point((int)this.room.maxPoints.X, (int)this.room.maxPoints.Y);
            PointF userPosition;
            // Getting the radioButton states
            bool onlyFront = true, device = true;
            int warningDistance = 20;
            lock (onlyFrontBtn)
            {
                onlyFront = onlyFrontBtn.Checked;
            }
            lock (pcBtn)
            {
                device = pcBtn.Checked;
            }
            lock (comboBox1)
            {
                warningDistance = int.Parse(comboBox1.Text);
            }
            if (device)
                userPosition = recognizer.changeChecker(onlyFront, device, warningDistance);
            else
            {
                string ip = "EOF";
                lock (textBox2)
                {
                    ip = textBox2.Text;
                }
                userPosition = recognizer.changeChecker(onlyFront, device, warningDistance, ip);
            }
            lock (this.graphics)
            {
                if (userPosition.X >= 0 && userPosition.Y >= 0)
                {
                    this.drawPoint((int)userPosition.X, (int)userPosition.Y, roomMax.X, roomMax.Y);
                    textBox1.AppendText("\r\n" + userPosition);
                }
            }
        }
        public float drawPanelLines(Pen myPen, Point[] points)
        {
            Point panelDimensions = new Point(panel1.Width, panel1.Height);
            Point margins = new Point(5, 5);
            Point[] newPoints = new Point[points.Length];
            Point maxValues = new Point((int)this.room.maxPoints.X, (int)this.room.maxPoints.Y);

            ratio = Math.Min(panelDimensions.X - 2f * margins.X, panelDimensions.Y - 2f * margins.Y) / Math.Max(maxValues.X, maxValues.Y);
            for (int i = 0; i < points.Length; i++)
            {
                PointF realValues = new PointF(ratio * (float)points[i].X, ratio * (float)points[i].Y);
                newPoints[i] = new Point((int)realValues.X + margins.X, panelDimensions.Y - margins.Y - (int)realValues.Y);
            }
            graphics.DrawLines(myPen, newPoints);
            return ratio;
        }
        public void drawPanelLines(Pen myPen, Point[] points, float ratio)
        {
            Point panelDimensions = new Point(panel1.Width, panel1.Height);
            Point margins = new Point(5, 5);
            Point[] newPoints = new Point[points.Length];
            Point maxValues = new Point(0, 0);
            for (int i = 0; i < points.Length; i++)
            {
                if (points[i].X >= maxValues.X)
                    maxValues.X = points[i].X;
                if (points[i].Y >= maxValues.Y)
                    maxValues.Y = points[i].Y;
            }
            for (int i = 0; i < points.Length; i++)
            {
                PointF realValues = new PointF(ratio * (float)points[i].X, ratio * (float)points[i].Y);
                newPoints[i] = new Point((int)realValues.X + margins.X, panelDimensions.Y - margins.Y - (int)realValues.Y);
            }
            graphics.DrawLines(myPen, newPoints);
        }
        public void drawPoint(int x, int y, int maxX, int maxY)
        {
            lock (graphics)
            {
                Point panelDimensions = new Point(panel1.Width, panel1.Height);
                Point margins = new Point(5, 5);
                Point realPanelDimensions = new Point(panelDimensions.X - 2 * margins.X, panelDimensions.Y - 2 * margins.Y);
                //PointF ratio = new PointF((float)realPanelDimensions.X / (float)maxX, (float)realPanelDimensions.Y / (float)maxY);
                // starting to draw the point
                //Pen p = new Pen(Color.Green);
                Point point = new Point((int)(x * ratio), (int)(realPanelDimensions.Y - y * ratio));
                graphics.FillEllipse(new SolidBrush(Color.Green), new Rectangle(point, new Size(3, 3)));
            }
        }
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            // Putting the text at the end of the application
            this.textBox1.SelectionStart = textBox1.Text.Length;
            this.textBox1.ScrollToCaret();

        }
        /// <summary>
        /// Defines the behavior of the program when a user press the
        /// Start button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            if (this.init())
            {
                this.initialRender();
                if (t != null && t.IsAlive)
                    t.Abort();
                t = new Thread(new ThreadStart(render));
                t.IsBackground = true;
                t.Start();
            }
            this.repaint = true;
        }
        /// <summary>
        /// Load the room defined in the XML document and initialize
        /// the WiimoteRecognizer object which is used to recognize
        /// the user position
        /// </summary>
        /// <returns>True if the room was correctly loaded and false otherwise</returns>
        private bool init()
        {
            if (graphics != null)
            {
                graphics.Dispose();
            }
            graphics = panel1.CreateGraphics();
            //Parsing the XML file
            xmlStatus = new XmlProcessor(xmlPath, schemaPath);

            bool status = xmlStatus.validate();
            if (!status)
            {
                textBox1.AppendText("Validation error. The XML file is not compatible with the XML Schema");
                return false;
            }
            else
            {
                textBox1.AppendText("Starting the XML processing");
                this.room = xmlStatus.processRoom(textBox1);
                textBox1.AppendText("\r\nThe XML file was succesfully read it");

                //Start the core application
                recognizer = new WiimoteRecognizer(room);
                return true;
            }
        }
        /// <summary>
        /// Render the room into the canvas defined in the UI
        /// </summary>
        private void initialRender()
        {
            // Create a new pen that we shall use for drawing the line
            Pen myPen = new Pen(Color.Black);
            // Drawing the shape of the room
            List<WiimoteLib.PointF> floatPoints = this.room.Points;
            List<Point> points = new List<Point>();
            foreach (WiimoteLib.PointF floatPoint in floatPoints)
            {
                Point point = new Point((int)floatPoint.X, (int)floatPoint.Y);
                points.Add(point);
            }
            points.Add(points.First());
            float ratio = drawPanelLines(myPen, points.ToArray());
            // Drawing the objects in the room
            myPen.Color = Color.Blue;
            foreach (RoomObject roomObject in room.RoomObjects)
            {
                List<WiimoteLib.PointF> cornerPoints = roomObject.CornerPoints;
                List<Point> intCornerPoints = new List<Point>();
                foreach (WiimoteLib.PointF cornerPoint in cornerPoints)
                {
                    Point point = new Point((int)cornerPoint.X, (int)cornerPoint.Y);
                    intCornerPoints.Add(point);
                }
                intCornerPoints.Add(intCornerPoints.First());
                drawPanelLines(myPen, intCornerPoints.ToArray(), ratio);
            }
            // Drawing doors
            myPen.Color = Color.Red;
            foreach (RoomDoor roomDoor in room.Doors)
            {
                WiimoteLib.PointF[] cornerPoints = roomDoor.Points;
                List<Point> intCornerPoints = new List<Point>();
                foreach (WiimoteLib.PointF cornerPoint in cornerPoints)
                {
                    Point point = new Point((int)cornerPoint.X, (int)cornerPoint.Y);
                    intCornerPoints.Add(point);
                }
                intCornerPoints.Add(intCornerPoints.First());
                drawPanelLines(myPen, intCornerPoints.ToArray(), ratio);
            }
        }
        private void render()
        {
            try
            {
                DrawPosition draw = new DrawPosition(drawUserPosition);
                while (true)
                {
                    panel1.Invoke(draw);
                    //Thread.Sleep(1000);
                }
            }
            catch (InvalidOperationException)
            {
                return;
            }
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            graphics.Dispose();
        }

        private void mobileBtn_CheckedChanged(object sender, EventArgs e)
        {
            if (mobileBtn.Checked)
                textBox2.ReadOnly = false;
            else
                textBox2.ReadOnly = true;
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (repaint)
            {
                this.initialRender();                
            }            
        }
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            base.OnPaint(e);
            if (repaint)
            {
                this.initialRender();                
            }            
        }

        private void loadXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog openDialog = new OpenFileDialog();
            openDialog.Title = "Open a XML file associated to a room";
            openDialog.Filter = "XML Files|*.xml";
            openDialog.InitialDirectory = @"D:\";
            openDialog.AddExtension = true;
            openDialog.CheckFileExists = true;
            openDialog.CheckPathExists = true;
            if (openDialog.ShowDialog() == DialogResult.OK)
            {
                this.xmlPath = openDialog.FileName;
            }
        }

    }
}
